/**
 ******************************************************************************
 * @file    qs100.c
 * @brief   qs100 program body
 ******************************************************************************
 * @attention QS-100 是一款基于芯翼 XY1100 的工业级 NB-IoT 无线通信模组，具有
 * 高性能、低功耗、多频段等多个产品优势，协议上完全兼容 R13 和 R14，软件升级支持
 *  R15，内嵌 TCP、UDP、MQTT、COAP 等多种通信协议栈，支持中国移动 OneNET ，中国
 *  联通云和中国电信 IoT 物联网云平台，方便客户应用。
 ******************************************************************************
 */
/* includes ------------------------------------------------------------------*/
#include "qs100.h"
/* Private includes ----------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include "gpio.h"
#include "usart.h"
#include "delay.h"
#include "debug.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define QS100_WAKEUP_H HAL_GPIO_WritePin(NB_WKUP_GPIO_Port, NB_WKUP_Pin, GPIO_PIN_SET)
#define QS100_WAKEUP_L HAL_GPIO_WritePin(NB_WKUP_GPIO_Port, NB_WKUP_Pin, GPIO_PIN_RESET)

#define SERVER_IP "112.125.89.8"
#define SERVER_PORT 45983
#define TCP_SEQUENCE 1
/* Private variables ---------------------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/**
 * @brief 芯片唤醒
* @param
* @return
*/
void QS100_Wakeup(void)
{
	/* 唤醒：RST_WAKE引脚高电平脉冲宽度大于 100us，小于 5s */
	QS100_WAKEUP_H;
	Delay_ms(5);
	QS100_WAKEUP_L;
	/* 引脚复位后，需要时间等芯片稳定运行 */
	Delay_ms(500);
	LOG_DEBUG("NB-IoT wake up!!!");
}

/**
 * @brief 串口发送AT指令
* @param
* @return
*/
void QS100_SendATCommand(char *cmd)
{
	/* 发送命令 */
	HAL_UART_Transmit(&huart3, (uint8_t *)cmd, strlen(cmd), 1000);
}

/**
 * @brief 接收AT响应
* @param
* @return
*/
void QS100_ReceiveATResponse(char *response)
{
	/* 接收响应 */
	char tempBuffer[256] = {0};
	uint16_t tempBufferLen = 0;
	uint8_t responseLen = 0;
	memset(response, 0, strlen(response));
	do
	{
		/* 接收数据 */
		HAL_UARTEx_ReceiveToIdle(&huart3, (uint8_t *)tempBuffer, 256, &tempBufferLen, 1000);
		/* 将临时缓存拼接到实际缓存里 */
		responseLen = strlen(response);
		memcpy(&response[responseLen], tempBuffer, tempBufferLen);
		/* 清空临时缓存 */
		memset(&tempBuffer, 0, tempBufferLen);
	}while (strstr(response, "OK") == NULL && strstr(response, "ERROR") == NULL);
}

/**
 * @brief 设备软重启
* @param
* @return
*/
void QS100_SoftReboot(void)
{
	char tempBuffer[256] = {0};
//	uint16_t tempBufferLen = 0;
	/* 发送软重启AT指令"AT+RB" */
	char *cmd = "AT+RB\r\n";
	QS100_SendATCommand(cmd);
	/* 接收处理数据，AT+RB 不会回复标志位ok或者error   等待满5s => 打印接收到的全部消息 => 中间会有多次idle信号 */
	HAL_UART_Receive(&huart3, (uint8_t *)tempBuffer, 256, 5000);
//	tempBufferLen = strlen(tempBuffer);
//	LOG_DEBUG("Soft reboot responses length:%u", tempBufferLen);
	/* 打印AT响应 */
//	LOG_DEBUG("Soft reboot responses:%s", tempBuffer);
	/* 下面是实际串口打印的内容 */
//	[qs100.c:95]AT responses length:97
//	[qs100.c:97]AT responses:
//	REBOOTING
//
//	+POWERON:2
//
//	^SIMST:1
//
//	+CGEV:ME PDN ACT 0
//
//	+CTZEU:+32,0,2025/08/18,08:53:42

}

/**
 * @brief 初始化QS100
 * @param
 * @return
 */
void QS100_Init(void)
{
	char response[128] = {0};
	/* 引脚已经初始化 */
	/* 芯片唤醒：高电平脉冲宽度大于 100us，小于 5s。 */
	QS100_Wakeup();
	/* 芯片软重启 */
	QS100_SoftReboot();
	/* 打开串口回显 */
	QS100_SendATCommand("ATE1\r\n");
	QS100_ReceiveATResponse(response);
	/* 打印AT响应 */
//	LOG_DEBUG("Turn on serial port echo:%s", response);

	/* 查询软件版本信息*/
	QS100_SendATCommand("AT+CGMR\r\n");
	QS100_ReceiveATResponse(response);
	/* 打印AT响应 */
//	LOG_DEBUG("Query software version information:%s", response);

	/* 串口打印如下 */
	//	[2025-08-18 21:10:40.452]# RECV ASCII>
	//	[qs100.c:96]AT responses length:46
	//	[qs100.c:98]AT responses:AT+RB
	//
	//	REBOOTING
	//
	//	+POWERON:2
	//
	//	^SIMST:1
	//
	//	[qs100.c:78]AT responses:
	//	OK
	//
	//
	//	[2025-08-18 21:10:40.527]# RECV ASCII>
	//	[qs100.c:78]AT responses:AT+CGMR
	//
	//	Software Version:V1100B10012R00C0001
	//
	//	OK
}

/**
 * @brief 是否连接了数据包交换机
 * @param
 * @return
 */
uint8_t QS100_IsPacketSwitchAttached(void)
{
	/* 发送查询"AT+CGATT?\r\n" */
	QS100_SendATCommand("AT+CGATT?\r\n");
	/* 接收AT响应 */
	char response[128] = {0};
	QS100_ReceiveATResponse(response);
	/* 判断是否连接成功 */
	if (strstr(response, "OK"))
	{
		return 0;
	}
	else
	{
		return 1;
	}
	/* 串口打印如下 */
	//	[qs100.c:78]AT responses:AT+CGATT?
	//
	//	+CGATT:1
	//
	//	OK
	//
	//	[qs100.c:214]Attach packet switch successfully
}

/**
 * @brief 创建客户端
 * @param
 * @return
 */
uint8_t QS100_CreateSocket(uint8_t *socket)
{
	/* 发送命令 */
	QS100_SendATCommand("AT+NSOCR=STREAM,6,0,1\r\n");
	/* 接收AT响应 */
	char response[128] = {0};
	QS100_ReceiveATResponse(response);
	/* 判断是否连接成功 */
	if (strstr(response, "OK"))
	{
		if (strchr(response,'0'))
		{
			*socket = 0;
		}
		else
		{
			*socket = 1;
		}
		return 0;
	}
	else
	{
		return 1;
	}
	/* 串口打印如下 */
	//	[qs100.c:78]AT responses:AT+NSOCR=STREAM,6,0,1
	//
	//	+NSOCR:0
	//
	//	OK
	//
	//	[qs100.c:228]Create socket successfully
}

/**
 * @brief 连接到服务端
 * @param
 * @return
 */
uint8_t QS100_IsServerConnected(uint8_t socket, char *serverIP, uint16_t serverPort)
{
	/* 拼接命令 */
	char cmd[50] = {0};
	sprintf(cmd, "AT+NSOCO=%d,%s,%d\r\n", socket, serverIP, serverPort);

	/* 发送命令 */
	QS100_SendATCommand(cmd);
	/* 接收AT响应 */
	char response[128] = {0};
	QS100_ReceiveATResponse(response);
	/* 判断是否连接成功 */
	if (strstr(response, "OK"))
	{
		return 0;
	}
	else
	{
		return 1;
	}
	/* 串口打印如下 */
	//	[qs100.c:78]AT responses:AT+NSOCO=0,112.125.89.8,45352
	//
	//	OK
	//
	//	[qs100.c:295]Connect server successfully
}

/**
 * @brief 向服务端发送数据
 * @param
 * @return
 */
uint8_t QS100_IsDataSentToServer(uint8_t socket, uint8_t *pData, uint16_t size)
{
//	/* 拼接命令 */
	char cmd[512] = {0};
	char hexData[size * 2 + 1];/* 十六进制字符串 */
	for (uint8_t i = 0; i < size; ++i)
	{
		sprintf(hexData + 2*i, "%02X", pData[i]);
	}
	hexData[2*size] = '\0';
	sprintf(cmd, "AT+NSOSD=%d,%d,%s,0x200,%d\r\n", socket, size, hexData,TCP_SEQUENCE);
//	LOG_DEBUG("HEX Data:%s", hexData);

	/* 发送命令 */
	QS100_SendATCommand(cmd);

	/* 接收AT响应 */
	char response[128] = {0};
	QS100_ReceiveATResponse(response);

	/* 判断是否连接成功 */
	if (strstr(response, "OK"))
	{
		return 0;
	}
	else
	{
		return 1;
	}
	/* 串口打印如下 */

}

/**
 * @brief 关闭客户端
 * @param
 * @return
 */
uint8_t QS100_IsSocketClosed(uint8_t socket)
{
	/* 拼接命令 */
	char cmd[50] = {0};
	sprintf(cmd, "AT+NSOCL=%d\r\n", socket);

	/* 发送命令 */
	QS100_SendATCommand(cmd);
	/* 接收AT响应 */
	char response[128] = {0};
	QS100_ReceiveATResponse(response);
	/* 判断是否连接成功 */
	if (strstr(response, "OK"))
	{
		return 0;
	}
	else
	{
		return 1;
	}
	/* 串口打印如下 */

}


/**
 * @brief 连接网络，发送数据
 * @param
 * @return
 */
uint8_t QS100_SendData(uint8_t *pData, uint16_t size)
{
	/* 判断当前PS附着状态（0=未附着，1=已附着）。附着说明已经连接到基站 */
	for (uint8_t i = 0; i < 10; ++i)
	{
		if (!QS100_IsPacketSwitchAttached())
		{
//			LOG_DEBUG("Attach packet switch successfully");
			break;
		}
		else if (i == 9 )
		{
			return 1;
		}
		else
		{
//			LOG_DEBUG("Fail to attach packet switch");
			Delay_ms(1000);
		}
	}

	/* 创建客户端 */
	uint8_t socket = 0xFF;
	for (uint8_t i = 0; i < 10; ++i)
	{
		if (!QS100_CreateSocket(&socket))
		{
//			LOG_DEBUG("Create socket successfully");
			break;
		}
		else if (i == 9 )
		{
			return 1;
		}
		else
		{
//			LOG_DEBUG("Fail to Create socket");
			Delay_ms(1000);
		}
	}

	/* 连接服务端 */
	for (uint8_t i = 0; i < 10; ++i)
	{
		if (!QS100_IsServerConnected(socket, SERVER_IP, SERVER_PORT))
		{
//			LOG_DEBUG("Connect server successfully");
			break;
		}
		else if (i == 9 )
		{
			return 1;
		}
		else
		{
//			LOG_DEBUG("Fail to Connect server");
			Delay_ms(1000);
		}
	}

	/* 向服务器发送数据 */
	for (uint8_t i = 0; i < 10; ++i)
	{
		if (!QS100_IsDataSentToServer(socket, pData, size))
		{
//			LOG_DEBUG("Send data to server successfully");
			break;
		}
		else if (i == 9 )
		{
			return 1;
		}
		else
		{
//			LOG_DEBUG("Fail to Send data to server");
			Delay_ms(1000);
		}
	}

	/* 关闭客户端 */
	for (uint8_t i = 0; i < 10; ++i)
	{
		if (!QS100_IsSocketClosed(socket))
		{
//			LOG_DEBUG("Close Socket successfully");
			break;
		}
		else if (i == 9 )
		{
			return 1;
		}
		else
		{
//			LOG_DEBUG("Fail to Close Socket");
			Delay_ms(1000);
		}
	}

	return 0;

}

/**
 * @brief QS100进入深度睡眠模式
 * @param
 * @return
 */
void QS100_GoIntoDeepSleep(void)
{
	QS100_SendATCommand("AT+FASTOFF=0\r\n");
	Delay_ms(100);
	LOG_DEBUG("NB-IoT enter low power mode!!!");
}
